package service

import (
	"errors"
	"time"

	"gitee.com/ysl729895/go-mall/internal/model"
	"gitee.com/ysl729895/go-mall/internal/repository"
	"github.com/golang-jwt/jwt/v5"
)

// 自定义错误类型
var (
	ErrUserExists       = errors.New("用户名已存在")
	ErrAuthFailed       = errors.New("用户名或密码错误")
	ErrUserNotFound     = errors.New("用户不存在")
	ErrInvalidPassword  = errors.New("密码不符合要求")
	ErrPasswordMismatch = errors.New("旧密码不正确")
)

type UserService interface {
	Register(username, password string) (*model.User, error)
	Login(username, password string) (*model.LoginResponse, error)
	GetUserInfo(username string) (*model.User, error)
	GetUserInfoByID(id uint) (*model.User, error) // 新增方法
	UpdateUserInfo(username, email string) (*model.User, error)
	ChangePassword(username, oldPassword, newPassword string) error
}

type userService struct {
	userRepo repository.UserRepository
	jwtKey   []byte
}

func NewUserService(userRepo repository.UserRepository, jwtKey string) UserService {
	return &userService{
		userRepo: userRepo,
		jwtKey:   []byte(jwtKey),
	}
}

func (s *userService) Register(username, password string) (*model.User, error) {
	_, err := s.userRepo.GetByUsername(username)
	if err == nil {
		return nil, ErrUserExists
	}

	user := &model.User{Username: username}
	if err := user.HashPassword(password); err != nil {
		return nil, err
	}

	if err := s.userRepo.Create(user); err != nil {
		return nil, err
	}

	return user, nil
}

func (s *userService) Login(username, password string) (*model.LoginResponse, error) {
	user, err := s.userRepo.GetByUsername(username)
	if err != nil {
		return nil, ErrAuthFailed
	}

	if err := user.CheckPassword(password); err != nil {
		return nil, ErrAuthFailed
	}

	token, err := s.generateJWT(user)
	if err != nil {
		return nil, err
	}

	return &model.LoginResponse{
		Token: token,
		User:  user,
	}, nil
}

func (s *userService) GetUserInfo(username string) (*model.User, error) {
	return s.userRepo.GetByUsername(username)
}

func (s *userService) GetUserInfoByID(id uint) (*model.User, error) {
	return s.userRepo.GetByID(id)
}

func (s *userService) UpdateUserInfo(username, email string) (*model.User, error) {
	user, err := s.userRepo.GetByUsername(username)
	if err != nil {
		return nil, ErrUserNotFound
	}

	user.Email = email
	if err := s.userRepo.Update(user); err != nil {
		return nil, err
	}

	return user, nil
}

func (s *userService) ChangePassword(username, oldPassword, newPassword string) error {
	user, err := s.userRepo.GetByUsername(username)
	if err != nil {
		return ErrUserNotFound
	}

	if err := user.CheckPassword(oldPassword); err != nil {
		return ErrPasswordMismatch
	}

	if err := user.HashPassword(newPassword); err != nil {
		return err
	}

	return s.userRepo.Update(user)
}

func (s *userService) generateJWT(user *model.User) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"user_id": user.ID,
		"exp":     time.Now().Add(time.Hour * 24).Unix(),
	})

	return token.SignedString(s.jwtKey)
}
